package com.xiaoc.bulldozer.springboot.config.interceptor;

import com.xc.framework.web.CookieUtils;
import com.xiaoc.bulldozer.common.ConfigKeys;
import com.xiaoc.bulldozer.common.Constant;
import com.xiaoc.bulldozer.common.dto.LoginUserDto;
import com.xiaoc.bulldozer.common.model.Action;
import com.xiaoc.bulldozer.common.service.cache.CommonConfigCacheService;
import com.xiaoc.bulldozer.facade.PriviledgeFacade;
import com.xiaoc.bulldozer.facade.UserFacade;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * 请求认证处理
 * 
 * @author lascala
 * 
 * @date 2017年03月01日
 */
public class AuthenticationHandler implements HandlerInterceptor {

    protected static final Logger logger = LoggerFactory.getLogger(AuthenticationHandler.class);

    @Resource
    private UserFacade userFacade;

    @Resource
    private PriviledgeFacade priviledgeFacade;
    
    @Resource(name = "commonConfigService")
    private CommonConfigCacheService commonConfigService;

    /**
     * 在业务处理器处理请求之前被调用 如果返回false 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链 如果返回true
     * 执行下一个拦截器,直到所有的拦截器都执行完毕 再执行被拦截的Controller 然后进入拦截器链,
     * 从最后一个拦截器往回执行所有的postHandle() 接着再从最后一个拦截器往回执行所有的afterCompletion()
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String sessionId = CookieUtils.getCookieValue(request, Constant.COOKIE_SESSION_ID);
        if (StringUtils.isBlank(sessionId)) {
            redirectUrl(request, response, request.getContextPath() + "/gotoLogin");
            return false;
        }

        LoginUserDto loginUserDto = userFacade.getCurrentLoginUser(sessionId);
        if (loginUserDto == null) {
            redirectUrl(request, response, request.getContextPath() + "/gotoLogin");
            return false;
        }

        userFacade.updateSession(sessionId);

        // 根据roleId获取actionList
        boolean isAuthentication = false;
        String path = request.getRequestURI();
        List<Action> actionList = priviledgeFacade.getActionListByUserId(loginUserDto);
        for (Action action : actionList) {
            if (action != null && action.getUrl().equals(path)) {
                isAuthentication = true;
                break;
            }
        }

        // 公共方法只要用户登录系统就可以使用，不需要分配功能权限
        String[] commonActions = new String[] {"/", "/logout", "/user/gotoEditpw", "/user/editpw" };
        for (String commonAction : commonActions) {
            if (commonAction.equals(path)) {
                isAuthentication = true;
                break;
            }
        }

        // 若无操作权限，则跳转至403页面
        if (isAuthentication == false) {
            logger.warn("user:" + loginUserDto.getId() + " request.url:" + path);
            forward(request, response, request.getContextPath() + "/common/exception?code=403&msg=没有访问权限");
            return false;
        }

        logger.info("userName:" + loginUserDto.getLoginName() + ", do:" + request.getRequestURI() + ", queryString:" + request.getQueryString());

        return true;
    }

    /**
     * 在业务处理器处理请求执行完成后,生成视图之前执行的动作 可在modelAndView中加入数据，比如当前时间
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (modelAndView != null) {
            String sessionId = CookieUtils.getCookieValue(request, Constant.COOKIE_SESSION_ID);
            LoginUserDto loginUserDto = userFacade.getCurrentLoginUser(sessionId);
            modelAndView.addObject("loginUserDto", loginUserDto);
            modelAndView.addObject("systemTitle", commonConfigService.getValue(ConfigKeys.SYSTEM_TITLE));
            modelAndView.addObject("menuNodeList", priviledgeFacade.getMenuTree(loginUserDto, Action.ADMIN_SYSTEM));
            modelAndView.addObject("path", request.getRequestURI());
        }
    }

    /**
     * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
     * 
     * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

        // logger.info("==============执行顺序: 3、afterCompletion================");
    }

    public void forward(HttpServletRequest request, HttpServletResponse response, String url) {

        try {
            request.setCharacterEncoding("UTF-8");
            request.getRequestDispatcher(url).forward(request, response);
        } catch (Exception e) {
            logger.error("forward to " + url + " failed.", e);
            throw new RuntimeException("系统异常", e);
        }
    }

    protected void redirectUrl(HttpServletRequest request, HttpServletResponse response, String url) {
        try {
            response.sendRedirect(url);
        } catch (Exception e) {
            logger.error("redirect to " + url + " failed.", e);
        }
    }
}
